package com.leanit.pmc.common.util;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpSession;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Random;

public class VerifyCodeUtils {

    public static final String VERIFY_CODES = "1234567890ABCDEFGHIJK1234567890LNOPQRSTUVXYZ1234567890";
    private static final Logger logger = LoggerFactory.getLogger(VerifyCodeUtils.class);

    private static final int DEFAULT_IMG_WIDTH = 200;
    private static final int DEFAULT_IMG_HEIGHT = 80;
    private static final int DEFAULT_CODE_LENGTH = 4;

    /**
     * 使用系统默认字符源生成验证码
     *
     * @param verifySize 验证码长度
     * @return
     */
    public static String generateVerifyCode(int verifySize) {
        return generateVerifyCode(verifySize, VERIFY_CODES);
    }

    /**
     * 使用指定源生成验证码
     *
     * @param verifySize 验证码长度
     * @param sources    验证码字符源
     * @return
     */
    public static String generateVerifyCode(int verifySize, String sources) {
        if (sources == null || sources.length() == 0) {
            sources = VERIFY_CODES;
        }
        int codesLen = sources.length();
        Random rand = new Random(System.currentTimeMillis());
        StringBuilder verifyCode = new StringBuilder(verifySize);
        for (int i = 0; i < verifySize; i++) {
            verifyCode.append(sources.charAt(rand.nextInt(codesLen - 1)));
        }
        return verifyCode.toString();
    }

    /**
     * 生成指定验证码图像文件
     *
     * @param w
     * @param h
     * @param outputFile
     * @param code
     * @throws IOException
     */
    public static void outputImage(int w, int h, File outputFile, String code) throws IOException {
        if (outputFile == null) {
            return;
        }
        File dir = outputFile.getParentFile();
        if (!dir.exists()) {
            dir.mkdirs();
        }
        try {
            outputFile.createNewFile();
            FileOutputStream fos = new FileOutputStream(outputFile);
            outputImage(w, h, fos, code);
            fos.close();
        } catch (IOException e) {
            throw e;
        }
    }

    /**
     * 输出指定验证码图片流
     *
     * @param w
     * @param h
     * @param os
     * @param code
     * @throws IOException
     */
    public static void outputImage(int w,
                                   int h,
                                   OutputStream os,
                                   String code) throws IOException {
        BufferedImage image = generateImage(w, h, code);
        ImageIO.write(image, "jpg", os);
    }

    /**
     * 生成验证码图片
     *
     * @param w
     * @param h
     * @param code
     * @throws IOException
     */
    public static BufferedImage generateImage(int w,
                                              int h,
                                              String code) throws IOException {
        int verifySize = code.length();
        BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
        Random rand = new Random();
        Graphics2D g2 = image.createGraphics();
        Color[] colors = new Color[4];
        Color[] colorSpaces = new Color[]{Color.red,
                Color.blue, Color.orange,
                Color.black, Color.green};
        for (int i = 0; i < colors.length; i++) {
            Color color = colorSpaces[rand.nextInt(colorSpaces.length)];
            boolean colorExist = false;
            for (int j = 0; j < i; j++) {
                if (colors[j] == color) {
                    i--;
                    colorExist = true;
                    break;
                }
            }
            if (!colorExist) {
                colors[i] = color;
            }
        }
        //Paint linearPaint2 = new LinearGradientPaint(0, 0, w, h, new float[]{0.2f, .4f, .6f, .8f, .9f}, colors);
        //Paint linearPaint2 = new LinearGradientPaint(0, 0, w, h, new float[]{0.3f, .6f, .8f, .9f}, new Color[]{Color.BLUE, Color.BLACK, Color.GREEN, Color.BLUE});
        //设置图片背景
        g2.setPaint(Color.LIGHT_GRAY);
        g2.fillRect(0, 0, w, h);
        //设置图片渐变背景
        //g2.setPaint(linearPaint);
        //g2.fillRoundRect(0, 0, w, h, 5, 5);
        // 添加噪点
        float yawpRate = 0.02f;// 噪声率
        int area = (int) (yawpRate * w * h);
        for (int i = 0; i < area; i++) {
            int x = rand.nextInt(w);
            int y = rand.nextInt(h);
            image.setRGB(x, y, rand.nextInt(255));
        }

        //g2.setPaint(linearPaint2);
        g2.setPaint(Color.RED);
        int fontSize = Math.min(w / verifySize, h);
        Font[] fonts = {new Font("微软雅黑", Font.BOLD, fontSize)};

        char[] chars = code.toCharArray();
        for (int i = 0; i < verifySize; i++) {
            g2.setFont(fonts[rand.nextInt(fonts.length)]);
//            AffineTransform affine = new AffineTransform();
//            affine.setToRotation(Math.PI / 4 * rand.nextDouble() * (rand.nextBoolean() ? 1 : -1), (w / verifySize) * i + fontSize / 2, h / 2);
//            g2.setTransform(affine);
            g2.setPaint(colors[i]);
            g2.drawChars(chars, i, 1, (w / verifySize) * i + 7, h / 2 + fontSize / 2);
        }
        g2.dispose();
        return image;
    }

    /**
     * 生成验证码图片
     *
     * @param w
     * @param h
     */
    public static VerifyBean generateVerify(int w, int h, int verifySize) {
        VerifyBean verify = null;
        try {
            String code = generateVerifyCode(verifySize);
            BufferedImage img = generateImage(w, h, code);
            verify = new VerifyBean();
            verify.setVerifyCode(code);
            verify.setImgBuffer(img);
        } catch (Exception e) {
            logger.error("生成错误码异常", e);
        }
        return verify;
    }

    /**
     * 生成验证码图片
     */
    public static VerifyBean generateVerify() {
        return generateVerify(DEFAULT_IMG_WIDTH, DEFAULT_IMG_HEIGHT, DEFAULT_CODE_LENGTH);
    }

    /**
     * 验证验证码
     *
     * @param session
     * @param code
     * @return
     */
    public static boolean verifyCode(HttpSession session, String code) {
        return StringUtils.isNotEmpty(code) && code.trim().equals(session.getAttribute("VERIFY_CODE_PMC"));
    }

    /**
     * 验证验证码,忽视大小写
     *
     * @param session
     * @param code
     * @return
     */
    public static boolean verifyCodeIgnoreCase(HttpSession session, String code) {
        return StringUtils.isNotEmpty(code) && code.trim().toLowerCase().equals(((String) session.getAttribute("VERIFY_CODE_PMC")).toLowerCase());
    }


}